// LoggerAPI.cpp : Defines the entry point for the application.
//

#include <iostream>
#include "LogApiImpl.hpp"
#include "../Common/Util.hpp"
#include "../Common/SocketHelper.hpp"

namespace cybertron {

	LogApiImpl *LogApiImpl::_instance = new LogApiImpl();

	LogApiImpl::LogApiImpl()
		: _net_appender_enabled(false)
		, _lock()
		//, _default_category("default")
		, _log_sender(NULL)
		, _log_encoder(NULL)
		, _has_rate_limit(false)
	{
		_item_remote_queue = new SafeQueue<LogItem>(1024 * 16);
		_item_local_queue = new SafeQueue<LogItem>(1024 * 16);
		_packet_queue = new SafeQueue<NetPacket>(1024 * 16);

		_log_local_writer = new LogLocalWriter(_item_local_queue);
	}

	LogApiImpl::~LogApiImpl()
	{
		std::lock_guard<std::mutex> lock(_lock);
		if (_net_appender_enabled) {
			_log_sender->stop();
			_log_encoder->stop();

			delete _log_sender;
			delete _log_encoder;

			SocketHelper::destroy();
		}

		_log_local_writer->stop();
		delete _log_local_writer;

		delete _item_remote_queue;
		delete _item_local_queue;
		delete _packet_queue;
	}

	int LogApiImpl::set_rate_limit(uint64_t rate_per_sec, uint64_t burst_size)
	{
		std::lock_guard<std::mutex> lock(_lock);
		if (_has_rate_limit) {
			std::cout << "the rate limit of log has already been set\n";
			return -1;
		}
		_token_bucket = TokenBucket(rate_per_sec, burst_size);
		_has_rate_limit = true;
		return 0;
	}

	int LogApiImpl::enable_net_appender(const std::string &ip, unsigned short port)
	{
		std::lock_guard<std::mutex> lock(_lock);
		if (!_net_appender_enabled) {
			SocketHelper::init();

			//disable the ip check to avoid the service does not exist when the client starts
			//if (!SocketHelper::is_valid_address(ip.c_str())) {
			//	SocketHelper::destroy();
			//	return -1;
			//}
			_net_appender_enabled = true;

			_log_encoder = new MsgEncoder(_item_remote_queue, _packet_queue);
			_log_sender = new LogSender(ip, port, _packet_queue);

			_log_encoder->start();
			_log_sender->start();
		}
		return 0;
	}

	int LogApiImpl::enable_console_appender()
	{
		std::lock_guard<std::mutex> lock(_lock);
		_log_local_writer->start();
		return _log_local_writer->enable_console();
	}

	int LogApiImpl::enable_file_appender(const std::string & file_path)
	{
		std::lock_guard<std::mutex> lock(_lock);
		_log_local_writer->start();
		return _log_local_writer->enable_file(file_path);
	}

	void LogApiImpl::log(LOG_LEVEL level, const char * category, const char * producer, const char * message)
	{
		if (_has_rate_limit && !_token_bucket.consume(1)) {
			std::cout << "log acceed rate limit\n";
			return;
		}
		std::string category_s = category ? (*category == '\0' ? "blank-category" : category) : "blank-category";
		std::string producer_s = producer ? (*producer == '\0' ? "blank-producer" : producer) : "blank-producer";
		std::string message_s = message ? (*message == '\0' ? "blank-message" : message) : "blank-message";

		LogItemV1 *item_v1_local = new LogItemV1(category_s, producer_s, level_to_string(level), message_s);
		LogItemV1 *item_v1_remote = new LogItemV1(*item_v1_local);

		if (!_item_remote_queue->enqueue(item_v1_remote, 0)) {
			delete item_v1_remote;
		}

		if (!_item_local_queue->enqueue(item_v1_local, 0)) {
			delete item_v1_local;
		}
	}

	std::string LogApiImpl::level_to_string(LOG_LEVEL level)
	{
		switch (level)
		{
		case LOG_LEVEL_DEBUG:
			return "DEBUG";
			break;
		case LOG_LEVEL_INFO:
			return "INFO";
			break;
		case LOG_LEVEL_WARN:
			return "WARN";
			break;
		case LOG_LEVEL_ERROR:
			return "ERROR";
			break;
		case LOG_LEVEL_FATAL:
			return "FATAL";
			break;
		default:
			return "DEBUG";
			break;
		}
	}
}


